#include <scene.h>

#include <assert.h>

struct object_node
{
  listnode_t node;
  object_t *object;
};


scene_t *
scene_new( void )
{
  scene_t *scene = calloc( 1, sizeof(scene_t) );

  assert( scene != NULL );

  scene->objects = list_new();

  return scene;
}

void
scene_free( scene_t *scene )
{
  assert( scene != NULL );
  assert( scene->objects != NULL );

  list_free( scene->objects );
  free( scene );
}

static int
scene_cmp_object( const listnode_t *a, const listnode_t *b )
{
  assert( a != NULL );
  assert( b != NULL );

  struct object_node *i, *j;

  i = (struct object_node *)a;
  j = (struct object_node *)b;

  assert( i->object != NULL );
  assert( j->object != NULL );

  if ( i->object->depth < j->object->depth )
    return -1;
  else if ( i->object->depth == j->object->depth )
    return 0;
  else
    return 1;
}

static int
scene_cmp_object_reverse( const listnode_t *a, const listnode_t *b )
{
  return -1 * scene_cmp_object( a, b );
}


void
scene_add_object( scene_t *scene, object_t *object )
{
  assert( scene != NULL );
  assert( object != NULL );

  struct object_node node;
  node.node.next = node.node.prev = NULL;
  node.object = object;

  list_insert_in_order( scene->objects, node, scene_cmp_object_reverse );
}

void
scene_render( scene_t *scene, surface_t *surface )
{
  assert( scene != NULL );
  assert( surface != NULL );

  struct object_node *node;

  for_each_list_element( scene->objects, node )
    {
      object_draw( node->object, surface );
    }
}

/**
 * Free every object from the scene, also clears it.
 */
void
scene_free_objects( scene_t *scene )
{
  assert( scene != NULL );
  struct object_node *node;

  for_each_list_element( scene->objects, node )
    {
      object_free( node->object );
      node->object = NULL;
    }
  scene_clear_objects( scene );
}

/**
 * Remove every object from scene.
 */
void
scene_clear_objects( scene_t *scene )
{
  assert( scene != NULL );
  list_clear( scene->objects );
}
